#pragma once 
#include <iostream>
#include <functional>
#include<string>
#include <unordered_map>
#include<unistd.h>
#include <assert.h>

#include "Socket.hpp"
#include "Epoll.hpp"
#include "Protocol.hpp"


namespace wyl 
{
    class Connection;
    class TcpServer;

    using func_t = std::function<void(Connection*)> ;
    using call_back_t = std::function<void(Connection* , std::string)>;
    class Connection
    {
    public:
        Connection(int sock = -1): _sock(sock) ,_tsvr(nullptr)
        {}

        void SetCallBack(func_t recv_cb,func_t send_cb,func_t except_cb)
        {
            _recv_cb = recv_cb;
            _send_cb = send_cb;
            _except_cb = except_cb;
        }

        ~Connection()
        {
            
        }
    public:
        int _sock; 
        func_t _recv_cb; //接收的回调函数 
        func_t _send_cb; //发送的回调函数
        func_t _except_cb; //异常的回调函数

        std::string _inbuff;  //输入缓冲区
        std::string _outbuff; //输出缓冲区

        TcpServer* _tsvr; //回调指针
    };



    const static int PORT = 8081; 
    class TcpServer
    {
        const int static gnum = 128;
    public: 
        TcpServer(uint16_t port = PORT,int revs_num = gnum) : _port(port),_revs_num(revs_num)
        {
            //第一步，绑定listen套接字
            _listen_sock = Socket::GetSocket();
            Socket::Bind(_listen_sock,_port); 
            Socket::Listen(_listen_sock);

            //第二步，创建Epoll对象
            _ep.CreateEoll(); 

            //第三步，讲listen套接字添加进epoll对象中
            AddConnection(_listen_sock,std::bind(&TcpServer::Accepter,this,std::placeholders::_1), nullptr , nullptr); 

            //第四步，为存储事件的数组初始化
            _revs = new struct epoll_event[_revs_num];
        }

        void AddConnection(int sock , func_t recv_cb, func_t send_cb , func_t except_cb)
        {
            //0.设置sock非阻塞等待 
            Socket::SetNoneBlock(sock);
            //1.建立一个连接对象,并绑定sock
            Connection* conn = new Connection(sock); 
            //2.设置回调函数
            conn->SetCallBack(recv_cb,send_cb,except_cb);
            //3.设置回调指针 
            conn->_tsvr = this ; 
            //4.添加到把连接epoll中,EPOLLIN读事件，EPOLLET 设置ET模式
            _ep.AddSockToEpoll(sock,EPOLLIN | EPOLLET) ;
            //5.把sock 和对应的连接添加进哈希映射
            _connections.insert(std::make_pair(sock,conn));
        }

        void Accepter(Connection* conn)
        {
            while(true)
            {
                int accept_errno = 0;
                std::string client_ip;
                uint16_t client_port;
                int sock = Socket::Accept(conn->_sock,&client_ip,&client_port,&accept_errno);
                
                //错误情况
                if(sock < 0)
                {
                    if(accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                        break; 
                    else if(accept_errno == EINTR) continue;  //读取时中断情况
                    else
                    {
                        //accept异常情况
                        ELOG("listen sock reading failed  %d : %s \n",errno, strerror(errno));
                        ELOG("sock : %d , listen sock : %d ,  conn sock :  %d \n",sock,_listen_sock,conn->_sock);
                        break;
                    }

                }
  
                if(sock >= 0)
                {
                    //accept成功
                    AddConnection(sock, std::bind(&TcpServer::Recver,this,std::placeholders::_1),
                                    std::bind(&TcpServer::Sender,this,std::placeholders::_1),
                                    std::bind(&TcpServer::Excepter,this,std::placeholders::_1));
                    DLOG("accept client # %d success \n",sock); 
                }
            }
        }

        //修改对读写事件的关心
        void EnableReadWrite(Connection* conn, bool Isread, bool Iswrite)
        {
            uint32_t event = (Isread ? EPOLLIN : 0 ) || (Iswrite ? EPOLLOUT : 0);
            bool res = _ep.ModSockFromEpoll(conn->_sock,event); 
            assert(res);
        }

        void Recver(Connection* conn)
        {
           char buff[1024] = {0};
           bool err = false; //记录是否出错
           while(true)
           {
                int n = recv(conn->_sock,buff,sizeof(buff) - 1 , 0 ); 
                if(n < 0)
                {
                    //已经读完的情况
                    if(errno == EAGAIN || errno == O_NONBLOCK) break;
                    else if(errno == EINTR) continue; //读取被中断，重新读取
                    {
                        //读取异常
                        ELOG("%d recv failed ， errno : %d : %s \n",conn->_sock,errno,strerror(errno));
                        err = true;
                        conn->_except_cb(conn);
                        err = true;
                        break;
                    }
                }else if(n == 0 )
                {
                    DLOG("client# %d quit.....\n",conn->_sock);
                    conn->_except_cb(conn);
                    break;
                }else 
                {
                    //读取成功
                    buff[n] = 0;
                    conn->_inbuff += buff; 
                }
           }
           if(!err)
           {
                //没有出错，分割缓冲区的字符串
                std::vector<std::string> out;
                SpliteMessage(conn->_inbuff,&out); 
                //处理分割出来的字符串
                for(auto& msg : out)
                {
                    _cb(conn,msg);
                }
                
           }
        }
        void Sender(Connection* conn)
        {
            while(true)
            {
                int n = send(conn->_sock,conn->_outbuff.c_str(),sizeof(conn->_outbuff),0); 
                if(n > 0) 
                {
                    //0 - n的部分发送成功
                    conn->_outbuff.erase(0 , n);
                    if(conn->_outbuff.empty()) break;
                }else 
                {
                    //已经写完了
                    if(errno == EAGAIN || errno == O_NONBLOCK) break;
                    else if(errno == EINTR) continue; //IO中断
                    else
                    {
                        //写入异常
                        ELOG("%d send failed ， errno : %d : %s \n",conn->_sock,errno,strerror(errno));
                        conn->_except_cb(conn);
                        break;
                    }
                }
            }
            //如果输出缓冲区为空，那么关闭掉对写事件的关心
            if(conn->_outbuff.empty()) EnableReadWrite(conn,true,false);
            else EnableReadWrite(conn,true,true); //否则继续关心写入事件
        }
        void Excepter(Connection* conn)
        {
            if(!IsExistsConnection(conn->_sock)) return ; //连接不在哈希中
            //移除事件关心
            _ep.DelSockFromEpoll(conn->_sock,0);
            _connections.erase(conn->_sock); 
            close(conn->_sock);
            delete conn;
            DLOG("Excepter 回收完毕，所有的异常情况\n");
        }

        void LoopOnce()
        {
            int n = _ep.WaitEpoll(_revs,_revs_num);
            for(int i = 0 ; i < n ; i++)
            {
                int sock = _revs[i].data.fd;
                uint32_t event = _revs[i].events;

                //异常统一处理
                if(event & EPOLLHUP) event |= (EPOLLIN | EPOLLOUT);
                if(event & EPOLLERR) event |= (EPOLLIN | EPOLLOUT);

                if(event & EPOLLIN)
                {
                    //连接存在且回调函数不为空
                    if(IsExistsConnection(sock) && _connections[sock]->_recv_cb != nullptr)
                        _connections[sock]->_recv_cb(_connections[sock]);//调用回调函数
                }

                if(event & EPOLLOUT)
                {
                    //连接存在且回调函数不为空
                    if(IsExistsConnection(sock) && _connections[sock]->_send_cb != nullptr)
                        _connections[sock]->_send_cb(_connections[sock]);//调用回调函数
                }
            }
        }

        void Start(call_back_t cb)
        {
            //初始化处理请求的函数
            _cb = cb;
            while(true)
            {
                LoopOnce();
            }
        }

        ~TcpServer()
        {
            if(_listen_sock >= 0) close(_listen_sock);
            if(_revs != nullptr) delete [] _revs;
        }
    private:
        bool IsExistsConnection(int sock)
        {
            auto it = _connections.find(sock);
            if(it == _connections.end()) return false;
            return true;
        }
    private:
        int _listen_sock; 
        uint16_t _port; 
        Epoll _ep;

        std::unordered_map<int,Connection*>  _connections;
        struct epoll_event * _revs; 
        int _revs_num;


        //应用层上的处理函数
        call_back_t _cb;
    };


};